import { AxiosRequestConfig, AxiosResponse, AxiosPromise } from '../types'
import { parseResponseHeaders } from '../helpers/util'
import { createError } from '../helpers/error'

export default function xhr(config: AxiosRequestConfig): AxiosPromise {
  return new Promise((res, rej) => {
    const { data = null, url, method = 'get', responseType, timeout } = config

    const request = new XMLHttpRequest()

    const headers = config.headers

    console.log(headers.test)

    if (responseType) {
      request.responseType = responseType
    }

    if (timeout) {
      request.timeout = timeout
    }

    // 使用非空断言
    request.open(method.toUpperCase(), url!, true)

    request.onreadystatechange = () => {
      if (request.readyState !== 4) {
        return
      }

      // 当请求超时或网络状态异常时status为0
      if (request.status === 0) {
        return
      }

      const responseHeaders = parseResponseHeaders(request.getAllResponseHeaders())
      const responseData =
        responseType && responseType !== 'text' ? request.response : request.responseText
      const response: AxiosResponse = {
        data: responseData,
        status: request.status,
        statusText: request.statusText,
        headers: responseHeaders,
        config,
        request
      }
      handleResponseStatus(response)
    }

    // 当网络出现异常时会触发onerror事件,此时不会有response
    request.onerror = () => {
      rej(createError('Network Error', config, null, request))
    }

    // 超时情况, 此时不会有response
    request.ontimeout = () => {
      createError(`Timeout of ${config.timeout} ms exceeded`, config, 'ECONNABORTED', request)
    }

    Object.keys(headers).forEach((name: string) => {
      request.setRequestHeader(name, headers[name])
    })

    request.setRequestHeader('test', '')

    request.send(data)

    function handleResponseStatus(response: AxiosResponse): any {
      if (response.status >= 200 && response.status < 300) {
        return res(response)
      } else {
        return rej(
          createError(
            `Request failed with status code ${response.status}`,
            config,
            null,
            request,
            response
          )
        )
      }
    }
  })
}
